package luceneutil;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import javax.swing.text.Document;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.core.SimpleAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.facet.old.ScoredDocIdsUtils;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.queryparser.xml.builders.NumericRangeQueryBuilder;
import org.apache.lucene.queryparser.xml.builders.TermQueryBuilder;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.search.highlight.SimpleSpanFragmenter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.primefaces.component.paginator.PaginatorElementRenderer;

import entities.Key;
import entities.KeySeacher;
import entities.MySim;
import entities.V100;
import entities.VnScoreDoc;
import applicationutil.ApplicationConstant;
import applicationutil.ApplicationUtil;

public class V100LunceneWorker {
	private IndexWriter writer;
	private String indexPath;

	public V100LunceneWorker(String indexPath) {
		// TODO Auto-generated constructor stub
		this.indexPath = indexPath;
	}

	private static V100LunceneWorker v100LunceneWorker;

	/*
	 * public static V100LunceneWorker getInstance(){
	 * if(v100LunceneWorker==null){ v100LunceneWorker=new
	 * V100LunceneWorker(ApplicationConstant.INDEX_PATH);
	 * v100LunceneWorker.createIndex(); v100LunceneWorker.createIndexWriter(); }
	 * return v100LunceneWorker; }
	 */
	/*
	 * tao noi luu index
	 */
	public void createIndex() {
		try {
			boolean create = true;
			File indexDirFile = new File(this.indexPath);
			if (indexDirFile.exists() && indexDirFile.isDirectory()) {
				create = false;
			}

			Directory dir = FSDirectory.open(indexDirFile);
			Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_46);
			IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_46,
					analyzer);
			if (create) {
				// Create a new index in the directory, removing any
				// previously indexed documents:
				iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
			} else
				iwc.setOpenMode(IndexWriterConfig.OpenMode.APPEND);
			IndexWriter writer = new IndexWriter(dir, iwc);
			writer.commit();
			writer.close(true);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void createIndexWriter() {

		try {
			File indexDirFile = new File(this.indexPath);
			Directory dir = FSDirectory.open(indexDirFile);
			Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_46);
			IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_46,
					analyzer);
			iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
			this.writer = new IndexWriter(dir, iwc);

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void update(V100 p) {
		deleteForUpdate(p);
		addV100(p);
	}

	/*
	 * xoa chi muc de cap nhat lai khi noi dung cap nhat moi
	 */
	public int deleteForUpdate(V100 p) {
		System.out.println("----vao delete for update  v100");
		try {
			NumericRangeQuery<Integer> num = NumericRangeQuery.newIntRange(
					ApplicationConstant.MYPAGE_FIELD_ID, 1, p.getPv100(),
					p.getPv100(), true, true);
			Directory directory = FSDirectory.open(new File(indexPath));
			IndexReader indexReader = DirectoryReader.open(directory);
			IndexSearcher indexSearcher = new IndexSearcher(indexReader);
			TopScoreDocCollector collector = TopScoreDocCollector.create(
					ApplicationConstant.MAX_DOC_GETED, true);
			indexSearcher.search(num, collector);
			ScoreDoc[] hitsDocs = collector.topDocs().scoreDocs;
			System.out.println("--so luong tim thay de xoa:" + hitsDocs.length);
			if (hitsDocs.length > 0) {
				org.apache.lucene.document.Document document = indexSearcher
						.doc(hitsDocs[0].doc);
				if (!document.get(ApplicationConstant.MYPAGE_FIELD_TEXT)
						.equals(p.getVv103())) {
					System.out.println("---delete document with pv100 = "
							+ p.getPv100());
					writer.deleteDocuments(num);
					writer.commit();
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return 0;
		}

		return 1;
	}

	/*
	 * xoa chi muc
	 */
	public int delete(V100 p) {
		System.out.println("----vao delete bang v100");
		try {
			NumericRangeQuery<Integer> num = NumericRangeQuery.newIntRange(
					ApplicationConstant.MYPAGE_FIELD_ID, 1, p.getPv100(),
					p.getPv100(), true, true);
			Directory directory = FSDirectory.open(new File(indexPath));
			IndexReader indexReader = DirectoryReader.open(directory);
			IndexSearcher indexSearcher = new IndexSearcher(indexReader);
			TopScoreDocCollector collector = TopScoreDocCollector.create(
					ApplicationConstant.MAX_DOC_GETED, true);
			indexSearcher.search(num, collector);
			ScoreDoc[] hitsDocs = collector.topDocs().scoreDocs;
			System.out.println("--so luong tim thay de xoa:" + hitsDocs.length);
			if (hitsDocs.length > 0) {
				org.apache.lucene.document.Document document = indexSearcher
						.doc(hitsDocs[0].doc);
				System.out.println("---delete document with pv100 = "
						+ p.getPv100());
				writer.deleteDocuments(num);
				writer.commit();

			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return 0;
		}

		return 1;
	}

	public int addV100(V100 p) {
		try {
			System.out.println("-----------------------indexing id:"
					+ p.getPv100());
			org.apache.lucene.document.Document document = new org.apache.lucene.document.Document();
			document.add(new IntField(ApplicationConstant.MYPAGE_FIELD_ID, p
					.getPv100(), Field.Store.YES));
			document.add(new TextField(ApplicationConstant.MYPAGE_FIELD_TEXT, p
					.getVv103(), Field.Store.YES));
			document.add(new TextField(
					ApplicationConstant.MYPAGE_FIELD_TEXT_TOKEN, p
							.getVv103token(), Field.Store.YES));
			TextField field = new TextField(
					ApplicationConstant.MYPAGE_FIELD_URL, p.getVv101(),
					Field.Store.YES);
			document.add(new TextField(
					ApplicationConstant.MYPAGE_FIELD_TEXT_NO_ACCENT, p
							.getVv103NoAccent(), Field.Store.YES));
			document.add(new TextField(ApplicationConstant.MYPAGE_FIELD_URL, p
					.getVv101(), Field.Store.YES));
			document.add(new TextField(
					ApplicationConstant.MYPAGE_FIELD_URL_INDEX,
					p.getUrlIndex(), Field.Store.YES));
			document.add(new TextField(ApplicationConstant.MYPAGE_FIELD_TITLE,
					p.getVv102(), Field.Store.YES));

			writer.addDocument(document);

			writer.commit();
			return 1;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return 0;
		}

	}

	/*
	 * add scoreDoc vai List, neu trung id document thi khong add
	 * la---------diem cao thi lay, chuyen list thanh hash
	 */
	public static void addScoreDoc(HashMap<Integer, VnScoreDoc> list,
			VnScoreDoc scoreDoc) {
		// neu hash map rong thi add scoredoc vao
		if (list.isEmpty())
			list.put(scoreDoc.getScoreDoc().doc, scoreDoc);
		else {
			// neu da co document ma diem document moi cao hon thi xoa doc cu,
			// add doc moi
			VnScoreDoc doc = list.get(new Integer(scoreDoc.getScoreDoc().doc));
			if (doc != null) {
				if (doc.getScoreDoc().score < scoreDoc.getScoreDoc().score) {
					list.remove(doc.getScoreDoc().doc);
					list.put(scoreDoc.getScoreDoc().doc, scoreDoc);
				}
			} else
				list.put(scoreDoc.getScoreDoc().doc, scoreDoc);
		}
	}

	/*
	 * search theo 3 field
	 */
	public List<VnScoreDoc> searchAll(KeySeacher keySeacher) throws Exception {
		System.out.println("---Luncene searching text all 3 field: "
				+ keySeacher.getNormalKey());
		long beginTime = System.currentTimeMillis();
		ApplicationUtil
				.setSession(ApplicationConstant.TIME_DURATION, beginTime);
		try {
			HashMap<Integer, VnScoreDoc> listScoreDocs = new HashMap<Integer, VnScoreDoc>();
			Directory directory = FSDirectory.open(new File(indexPath));
			IndexReader indexReader = DirectoryReader.open(directory);
			IndexSearcher indexSearcher = new IndexSearcher(indexReader);
			float weight = 1.1f;
			for (Key key : keySeacher.getListKeys()) {

				QueryParser queryParser = new QueryParser(Version.LUCENE_46,
						key.getFieldSearch(), new StandardAnalyzer(
								Version.LUCENE_46));
				Query q = null;
				String textQuery = "";
				/*
				 * xay dung query theo yeu cau tim kiem cua user
				 */
				if (keySeacher.getWebSiteSearch() != null
						&& keySeacher.getWebSiteSearch().length() > 1) {
					if (keySeacher.getMode() == 1)
						textQuery = ApplicationConstant.MYPAGE_FIELD_URL_INDEX
								+ ":\"" + keySeacher.getWebSiteSearch() + "\""
								+ " AND " + key.getFieldSearch() + ":("
								+ key.getTextSearch() + ")";
					else
						textQuery = ApplicationConstant.MYPAGE_FIELD_URL_INDEX
								+ ":\"" + keySeacher.getWebSiteSearch() + "\""
								+ " AND " + key.getFieldSearch() + ":\""
								+ key.getTextSearch() + "\"";
				} else {
					if (keySeacher.getMode() == 1)
						textQuery = key.getTextSearch();
					else
						textQuery = "\"" + key.getTextSearch() + "\"";
				}
				/*
				 * query tu khong muon tim
				 */
				if (keySeacher.getNotText() != null
						&& keySeacher.getNotText().length() > 0) {
					String notText = keySeacher.getNotText();
					if (key.getFieldSearch().equals(
							ApplicationConstant.MYPAGE_FIELD_TEXT_NO_ACCENT))
						notText = ApplicationUtil.removeAccent(notText);
					else if (key.getFieldSearch().equals(
							ApplicationConstant.MYPAGE_FIELD_TEXT_TOKEN))
						notText = ApplicationUtil.getToken(notText);
					textQuery += " -" + key.getFieldSearch() + ":" + "\""

					+ notText + "\"";
				}
				System.out.println("-----text query:" + textQuery);
				q = queryParser.parse(textQuery);
				TopScoreDocCollector collector = TopScoreDocCollector.create(
						ApplicationConstant.MAX_DOC_GETED, true);

				/*
				 * chinh diem uu tien giam dan theo thu tu uu tien
				 */
				weight -= 0.1f;
				indexSearcher.setSimilarity(new MySim(weight));
				indexSearcher.search(q, collector);
				ScoreDoc[] hitsDocs = collector.topDocs().scoreDocs;
				/*
				 * System.out.println("-----list reulst field " +
				 * key.getFieldSearch() + ": " + hitsDocs.length);
				 */
				for (ScoreDoc s : hitsDocs) {
					VnScoreDoc doc = new VnScoreDoc(s);
					doc.setFieldSearch(key.getFieldSearch());
					doc.setTextSearch(key.getTextSearch());
					/*
					 * System.out.println("-----------------doc:" +
					 * doc.getScoreDoc().doc);
					 */

					/*
					 * org.apache.lucene.document.Document document =
					 * indexSearcher .doc(doc.getScoreDoc().doc);
					 */
					/*
					 * System.out .println("----------------pv100:" + document
					 * .get(ApplicationConstant.MYPAGE_FIELD_ID));
					 * 
					 * System.out.println("-------------------score:" +
					 * doc.getScoreDoc().score);
					 */
					addScoreDoc(listScoreDocs, doc);
				}
			}
			/*
			 * SORT KET QUA THEO DIEM GIAM DAN
			 */
			List<VnScoreDoc> list = new ArrayList<VnScoreDoc>(
					listScoreDocs.values());
			Collections.sort(list);
			long endTime = System.currentTimeMillis();
			/*
			 * set session
			 */
			ApplicationUtil.setSession(ApplicationConstant.NUM_RESULT,
					listScoreDocs.size());

			System.out.println("---------Lucene has found "
					+ listScoreDocs.size() + " records");
			return list;

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}

	}

	/*
	 * get result từ scoredoc
	 */
	public List<V100> getResultList(int offset, int limit,
			List<VnScoreDoc> listScoreDocs) {
		System.out.println("---offset:" + offset);
		System.out.println("---limit:" + limit);
		List<V100> listPages = new ArrayList<V100>();

		Directory directory;
		try {
			directory = FSDirectory.open(new File(indexPath));
			IndexReader indexReader = DirectoryReader.open(directory);
			IndexSearcher indexSearcher = new IndexSearcher(indexReader);
			int max = offset + limit;
			if (listScoreDocs.size() < max)
				max = listScoreDocs.size();
			System.out.println("----max:" + max);
			/*
			 * in dam tu khoa
			 */
			for (int i = offset; i < max; i++) {
				VnScoreDoc vnScoreDoc = listScoreDocs.get(i);
				ScoreDoc s = vnScoreDoc.getScoreDoc();
				org.apache.lucene.document.Document document = indexSearcher
						.doc(s.doc);
				V100 p = new V100();
				p.setPv100(Integer.parseInt(document
						.get(ApplicationConstant.MYPAGE_FIELD_ID)));
				p.setVv103(document.get(ApplicationConstant.MYPAGE_FIELD_TEXT));
				p.setVv102(document.get(ApplicationConstant.MYPAGE_FIELD_TITLE));
				p.setVv101(document.get(ApplicationConstant.MYPAGE_FIELD_URL));
				// highlight mac dinh 1, neu k dc hightlight bang lucene neu k
				// dc nua thi cat chuoi dau tien
				// text-----------------------------------------------------------------------
				String srcText = "";
				String textSearch = vnScoreDoc.getTextSearch();
				if (vnScoreDoc.getFieldSearch().equals(
						ApplicationConstant.MYPAGE_FIELD_TEXT))
					srcText = p.getVv103();
				else if (vnScoreDoc.getFieldSearch().equals(
						ApplicationConstant.MYPAGE_FIELD_TEXT_NO_ACCENT))
					srcText = p.getVv103NoAccent();
				else
					srcText = p.getVv103token();
				System.out.println("----hightlight fieldsearch,textsearch:"
						+ vnScoreDoc.getFieldSearch() + "," + textSearch);
				String subContent = "";
				subContent = ApplicationUtil.getSubContentDefault(textSearch,
						p.getVv103());
				if (subContent == null || subContent.length() == 0) {
					System.out.println("-----dc highlight bang lucene");
					TermQuery query = new TermQuery(new Term(
							vnScoreDoc.getFieldSearch(), textSearch));
					TokenStream stream = new StandardAnalyzer(Version.LUCENE_46)
							.tokenStream(vnScoreDoc.getFieldSearch(),
									new StringReader(srcText));
					QueryScorer queryScorer = new QueryScorer(query,
							vnScoreDoc.getFieldSearch());
					Fragmenter fragmenter = new SimpleSpanFragmenter(
							queryScorer);
					SimpleHTMLFormatter formatter = new SimpleHTMLFormatter(
							"<label style=\"color:#551A8B;font-weight: bold;\" >",
							"</label>");
					Highlighter highlighter = new Highlighter(formatter,
							queryScorer);
					highlighter.setTextFragmenter(fragmenter);

					try {
						subContent = highlighter.getBestFragments(stream,
								srcText, 2, "...");
						System.out.println("----test hightlight:" + subContent);
					} catch (InvalidTokenOffsetsException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				if (subContent == null || subContent.length() == 0)
					subContent = ApplicationUtil.getBabSubContent(p.getVv103());

				p.setSubVV103(subContent.replace("_", " "));
				listPages.add(p);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return listPages;
	}

	public void close() throws IOException {
		if (writer != null)
			writer.close();
	}

}
